# Libuv空闲句柄 结合libuv的事件循环过程,在每个循环周期会执行 `uv__run_idle()`函数 ,如下图: ![](media/aHR0cDovL3Fpbml1LmppZWppZTAxLnRvcC9saWJ1djAwNS5wbmc.png) ## Demo ```c #include #include #include int64_t num = 0; void my_idle_cb(uv_idle_t* handle) { num++; if (num >= 10e6) { printf("idle stop, num = %ld\n", num); uv_idle_stop(handle); } } int main() { uv_idle_t idler; uv_idle_init(uv_default_loop(), &idler); printf("idle start, num = %ld\n", num); uv_idle_start(&idler, my_idle_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); return 0; } ``` 执行结果: ```c idle start, num = 0 idle stop, num = 10000000 ``` ## 空闲句柄的API函数 - 初始化句柄 ```c int uv_idle_init(uv_loop_t* loop, uv_idle_t* idle) ``` - 设置回调函数 ```c int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb) ``` - 停止 ```c int uv_idle_stop(uv_idle_t* idle) ``` 直接全局搜索uv_idle_init这个函数的话,是找不到它的,因为libuv做了很骚的操作,将idle、prepare以及check相关的函数都通过C语言的##连接符统一用宏定义了,并且在编译器预处理的时候产生对应的函数代码,具体源码如下: src\unix\loop-watcher.c文件内容 ```c #include "uv.h" #include "internal.h" #define UV_LOOP_WATCHER_DEFINE(name, type) \ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \ handle->name##_cb = NULL; \ return 0; \ } \ \ int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ if (uv__is_active(handle)) return 0; \ if (cb == NULL) return UV_EINVAL; \ QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \ handle->name##_cb = cb; \ uv__handle_start(handle); \ return 0; \ } \ \ int uv_##name##_stop(uv_##name##_t* handle) { \ if (!uv__is_active(handle)) return 0; \ QUEUE_REMOVE(&handle->queue); \ uv__handle_stop(handle); \ return 0; \ } \ \ void uv__run_##name(uv_loop_t* loop) { \ uv_##name##_t* h; \ QUEUE queue; \ QUEUE* q; \ QUEUE_MOVE(&loop->name##_handles, &queue); \ while (!QUEUE_EMPTY(&queue)) { \ q = QUEUE_HEAD(&queue); \ h = QUEUE_DATA(q, uv_##name##_t, queue); \ QUEUE_REMOVE(q); \ QUEUE_INSERT_TAIL(&loop->name##_handles, q); \ h->name##_cb(h); \ } \ } \ \ void uv__##name##_close(uv_##name##_t* handle) { \ uv_##name##_stop(handle); \ } UV_LOOP_WATCHER_DEFINE(prepare, PREPARE) UV_LOOP_WATCHER_DEFINE(check, CHECK) UV_LOOP_WATCHER_DEFINE(idle, IDLE) ``` 针对idle handle 宏定义展开后如下: ```c int uv_idle_init(uv_loop_t* loop, uv_idle_t* handle) { /* 初始化handle的类型,所属loop,设置UV_HANDLE_REF标志,并且把handle插入loop->handle_queue队列的队尾 */ uv__handle_init(loop, (uv_handle_t*)handle, UV_IDLE); handle->idle_cb = NULL; return 0; } int uv_idle_start(uv_idle_t* handle, uv_idle_cb cb) { /* 如果已经执行过start函数则直接返回 */ if (uv__is_active(handle)) return 0; /* 回调函数不允许为空 */ if (cb == NULL) return UV_EINVAL; /* 把handle插入loop中idle_handles队列,loop有prepare,idle和check三个队列 */ QUEUE_INSERT_HEAD(&handle->loop->idle_handles, &handle->queue); /* 指定回调函数,在事件循环迭代的时候被执行 */ handle->idle_cb = cb; /* 启动idle handle,设置UV_HANDLE_ACTIVE标记并且将loop中的handle的active计数加一, init的时候只是把handle挂载到loop,start的时候handle才处于激活态 */ uv__handle_start(handle); return 0; } int uv_idle_stop(uv_idle_t* handle) { /* 如果idle handle没有被启动则直接返回 */ if (!uv__is_active(handle)) return 0; /* 把handle从loop中相应的队列移除,但是还挂载到handle_queue中 */ QUEUE_REMOVE(&handle->queue); /* 清除UV_HANDLE_ACTIVE标记并且减去loop中handle的active计数 */ uv__handle_stop(handle); return 0; } /* 在每一轮循环中执行该函数,具体见uv_run */ void uv__run_idle(uv_loop_t* loop) { uv_idle_t* h; QUEUE queue; QUEUE* q; /* 把loop的idle_handles队列中所有节点摘下来挂载到queue变量 */ QUEUE_MOVE(&loop->idle_handles, &queue); /* while循环遍历队列,执行每个节点里面的函数 */ while (!QUEUE_EMPTY(&queue)) { /* 取下当前待处理的节点 */ q = QUEUE_HEAD(&queue); /* 取得该节点对应的整个结构体的基地址 */ h = QUEUE_DATA(q, uv_idle_t, queue); /* 把该节点移出当前队列 */ QUEUE_REMOVE(q); /* 重新插入loop->idle_handles队列 */ QUEUE_INSERT_TAIL(&loop->idle_handles, q); /* 执行对应的回调函数 */ h->idle_cb(h); } } /* 关闭这个idle handle */ void uv__idle_close(uv_idle_t* handle) { uv_idle_stop(handle); } ```